//@author A0083782W
#include "ActionList.h"

UserCommand PassedAction::reverse() {
	UserCommand undoCommand;
	undoCommand.setEvent (_myEvent);
	if (getOperationType() == OperationType::ADD) {
		undoCommand.setOperationType (OperationType::DELETE_BY_EVENT);
	}
	else if (getOperationType() == OperationType::DELETE_BY_NUMBER) {
		undoCommand.setOperationType (OperationType::ADD);
	}
	else {
		undoCommand.setOperationType (OperationType::MODIFY);
	}
	return undoCommand;
}

void PassedAction::setActionTime(const Time& newTime) {
	_actionTime = newTime;
}

void ActionList::reset() {
	_actionStack.clear();
	_actionStack.shrink_to_fit();
	midOfModify = false;
}

ActionList::ActionList() {
	reset();
}

ActionList& ActionList::get() {
	static ActionList newInstance;
	return newInstance;
}

const PassedAction& ActionList::operator[] (pos_int rightOperand) const{
	if (rightOperand > sizeOfActions() || sizeOfActions() == 0) {
		failProgram (ERR_ActionList::access_error);
	}

	bool insideModify = false;
	int listPos = 0;
	int currentAction = 0;
	for (int i = 0; i <(int)_actionStack.size() ; i++) {
		if (_actionStack[i].getOperationType() == OperationType::MODIFY) {
			if (insideModify == false) {
				insideModify = true;
			}
			else {
				insideModify = false;
				currentAction++;
			}
		}
		else {
			currentAction++;
		}
		if (currentAction == rightOperand + 1) {
			listPos = i;
			break;
		}
	}
	return _actionStack[listPos];
}


pos_int ActionList::size() const {
	return _actionStack.size();
}

pos_int ActionList::sizeOfActions() const {
	pos_int result = 0;
	pos_int modifyNum = 0;
	for (auto i:_actionStack) {
		if (i.getOperationType() == OperationType::ADD ||
			i.getOperationType() == OperationType::DELETE_BY_NUMBER ) {
			result++;
		}
		else {
			modifyNum++;
		}
	}
	result += modifyNum/2;
	return result;
}

bool ActionList::peek_isModify() const {
	if (_actionStack.size() != 0) {
		if (_actionStack[_actionStack.size() - 1].getOperationType() == OperationType::MODIFY ) {
			return true;
		}
	}
	return false;
}

void ActionList::push (const UserCommand& currentCommand) {
	PassedAction newAction;
	switch (currentCommand.getOperationType()) {
	case OperationType::ADD:
	case OperationType::DELETE_BY_NUMBER:
	case OperationType::MODIFY:
		newAction.setActionTime (currentCommand.getActionTime());
		newAction.setOperationType (currentCommand.getOperationType());
		newAction.setEvent (currentCommand.getEvent());	
		_actionStack.push_back (newAction);
			break;
	default:
		break;
	}
}

void ActionList::push (const Event& currentEvent, OperationType currentOperation ) {
	PassedAction newAction;
	switch (currentOperation) {
	case OperationType::ADD:
	case OperationType::DELETE_BY_NUMBER:
	case OperationType::MODIFY:
		newAction.setActionTime ();
		newAction.setOperationType (currentOperation);
		newAction.setEvent (currentEvent);
		_actionStack.push_back (newAction);
		break;
	default:
		break;
	}
}

UserCommand ActionList::pop() {
	UserCommand newCommand = _actionStack [_actionStack.size() - 1].reverse();
	if (newCommand.getOperationType() == OperationType::MODIFY) {
		if (_actionStack.size() == 1) {
			newCommand.setOperationType (OperationType::ADD);
		}
		else {
			if (midOfModify == false) {
				newCommand.setOperationType (OperationType::DELETE_BY_EVENT);
				midOfModify = true;
			}
			else {
				newCommand.setOperationType (OperationType::ADD);
				midOfModify =false;
			}
		}
	}
	if (_actionStack.size() == 0 ) {
		failProgram (ERR_ActionList::pop_error);
	}
	_actionStack.pop_back();
	return newCommand;
}

